#include "gd32f30x.h"
#include "stdint.h"
#include "stdio.h"
#include "DevicesDelay.h"
#include "DevicesUID.h"
#include "DevicesADC.h"


static uint16_t st_usADCDmaDatas[ADC0_SAMPLING_NUMBER][ADC0_SAMPLING_CHANNEL] = {0};


static void vADCDMAInit(void);


void vADCWatchdogInit(void)
{
//    /* enable GPIOA clock */
//    rcu_periph_clock_enable(RCU_GPIOC);
//    /* enable ADC clock */
//    rcu_periph_clock_enable(RCU_ADC2);

//    /* config the GPIO as analog mode */
//    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_3);


//    adc_deinit(ADC2);


//    /* ADC continuous function enable */
//    adc_special_function_config(ADC2, ADC_CONTINUOUS_MODE, ENABLE);
//    /* ADC scan function enable */
//    adc_special_function_config(ADC2, ADC_SCAN_MODE, DISABLE);
//    /* ADC data alignment config */
//    adc_data_alignment_config(ADC2, ADC_DATAALIGN_RIGHT);
//    /* ADC channel length config */
//    adc_channel_length_config(ADC2, ADC_REGULAR_CHANNEL, ADC1_SAMPLING_CHANNEL);

//    adc_regular_channel_config(ADC2, 0, ADC_SAMPLE_BATTERY_VOLTAGE, ADC1_SAMPLE_TIME);

//    adc_external_trigger_source_config(ADC2, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
//    adc_external_trigger_config(ADC2, ADC_REGULAR_CHANNEL, ENABLE);


//    /* enable ADC interface */
//    adc_enable(ADC2);
//    vDelayMs(10.0f);
//    /* ADC calibration and reset calibration */
//    adc_calibration_enable(ADC2);


//    nvic_irq_enable(ADC2_IRQn, 0, 0);

//    /* ADC analog watchdog threshold config */
//    /* Vadc = Vout * 0.055 */
//    adc_watchdog_threshold_config(ADC2, 20.0f * 0.055f * 4096.0f / 3.3f, 35.0f * 0.055f * 4096.0f / 3.3f);
//    /* ADC analog watchdog single channel config */
//    adc_watchdog_single_channel_enable(ADC2, ADC_SAMPLE_BATTERY_VOLTAGE);
//    /* 初始化完成后，先关闭，等待条件合适了再开启 */
//    vADCWatchdogSwitchSet(DISABLE);
//    /* ADC interrupt config */
//    adc_interrupt_enable(ADC2, ADC_INT_WDE);


//    /* ADC software trigger enable */
//    adc_software_trigger_enable(ADC2, ADC_REGULAR_CHANNEL);
}

/* 开启、关闭模拟看门狗 */
void vADCWatchdogSwitchSet(int8_t cState)
{
//    if(cState == DISABLE)
//    {
//        /* disable ADC analog watchdog */
//        ADC_CTL0(ADC2) &= ~ADC_CTL0_RWDEN;
//    }
//    else
//    {
//        /* enable ADC analog watchdog */
//        ADC_CTL0(ADC2) |= ADC_CTL0_RWDEN;
//    }
}

void vADCInit(void)
{
    /* enable GPIOA clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOD);
    rcu_periph_clock_enable(RCU_GPIOE);
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC0);
    rcu_periph_clock_enable(RCU_ADC1);


    /* configure GPIO pin（硬件二选一通道切换控制） */
    gpio_init(AD_CHANNEL_CHOICE_GPIO_Port,  GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, AD_CHANNEL_CHOICE_Pin);


    adc_deinit(ADC0);
    adc_deinit(ADC1);


    /* config ADC clock */
    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4);

    /* config the GPIO as analog mode */
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_0);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_1);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_2);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_3);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_4);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_5);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_6);
    gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_7);

    gpio_init(GPIOB, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_0);
    gpio_init(GPIOB, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_1);

    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_0);
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_1);
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_2);
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_3);
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_4);
    gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_10MHZ, GPIO_PIN_5);


    /* ADC mode config */
    adc_mode_config(ADC_MODE_FREE);

    /* ADC continuous function enable */
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);
    /* ADC scan function enable */
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_SAMPLING_CHANNEL);

    /* ADC regular channel config */
    adc_regular_channel_config(ADC0, 0, ADC_SAMPLE_DC12V_INDUCTIVE_CURRENT, ADC0_SAMPLE_TIME);
    adc_regular_channel_config(ADC0, 1, ADC_SAMPLE_DC12V_OUT_VOLTAGE,       ADC0_SAMPLE_TIME);
    adc_regular_channel_config(ADC0, 2, ADC_SAMPLE_DC24V_INDUCTIVE_CURRENT, ADC0_SAMPLE_TIME);
    adc_regular_channel_config(ADC0, 3, ADC_SAMPLE_DC24V_OUT_VOLTAGE,       ADC0_SAMPLE_TIME);

    // /* ADC trigger config */
    // adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T0_CH0);
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);


    /* ADC continuous function enable */
    adc_special_function_config(ADC1, ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC scan function enable */
    adc_special_function_config(ADC1, ADC_SCAN_MODE, DISABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, ADC1_SAMPLING_CHANNEL);

    adc_regular_channel_config(ADC1, 0, ADC_SAMPLE_AMBIENT_TEMPERATURE, ADC1_SAMPLE_TIME);

    adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
    adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);


    /* enable ADC interface */
    adc_enable(ADC0);
    vDelayMs(10.0f);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC0);

    /* enable ADC interface */
    adc_enable(ADC1);
    vDelayMs(10.0f);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC1);


    vADCDMAInit();


    /* ADC software trigger enable */
    // adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
    adc_software_trigger_enable(ADC1, ADC_REGULAR_CHANNEL);
}

static void vADCDMAInit(void)
{
    /* ADC_DMA_channel configuration */
    dma_parameter_struct dma_data_parameter = {0};

    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA0);

    /* ADC DMA function enable */
    adc_dma_mode_enable(ADC0);

    /* ADC DMA_channel configuration */
    dma_deinit(DMA0, DMA_CH0);

    /* initialize DMA single data mode */
    dma_data_parameter.periph_addr  = (uint32_t)(&ADC_RDATA(ADC0));
    dma_data_parameter.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_data_parameter.memory_addr  = (uint32_t)st_usADCDmaDatas;
    dma_data_parameter.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;  
    dma_data_parameter.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_data_parameter.number       = ADC0_SAMPLING_NUMBER * ADC0_SAMPLING_CHANNEL;
    dma_data_parameter.priority     = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH0, &dma_data_parameter);

    dma_circulation_enable(DMA0, DMA_CH0);

    /* enable DMA channel */
    dma_channel_enable(DMA0, DMA_CH0);
}

/*!
    \brief      ADC dma channel
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetDMAValue(uint8_t ucChannel)
{
#if 1
    uint16_t *pDatasHand = (uint16_t *)st_usADCDmaDatas;

    if(ucChannel >= ADC0_SAMPLING_CHANNEL)
        return 0.0f;

    pDatasHand += ucChannel;

    return ((float)(*pDatasHand)) * (3.3f / 4095.0f);

#else
    uint32_t uiValueSum = 0;
    uint16_t *pDatasHand = (uint16_t *)st_usADCDmaDatas;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF, i = 0;

    if(ucChannel >= ADC0_SAMPLING_CHANNEL)
        return 0.0f;

    pDatasHand += ucChannel;

    for(i = 0; i < ADC0_SAMPLING_NUMBER; ++i)
    {
        usValueNow  = *pDatasHand;
        uiValueSum += usValueNow;

        pDatasHand += ADC0_SAMPLING_CHANNEL;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    uiValueSum -= usValueMax + usValueMin;

    return ((float)uiValueSum / (ADC0_SAMPLING_NUMBER - 2) * (3.3f / 4095.0f));

#endif
}

/*!
    \brief      ADC channel sample
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetChannelValue(uint32_t adc_periph, uint8_t channel, uint32_t uiCnt)
{
    uint32_t uiValueSum = 0, i = 0;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF;


    /* ADC regular channel config */
    adc_regular_channel_config(adc_periph, 0, channel, ADC1_SAMPLE_TIME);


    /* 切换通道后，丢弃第一次转换的数据 */
    /* wait the end of conversion flag */
    while(!adc_flag_get(adc_periph, ADC_FLAG_EOC));
    /* clear the end of conversion flag */
    adc_flag_clear(adc_periph, ADC_FLAG_EOC);
    /* get regular channel sample value */
    adc_regular_data_read(adc_periph);


    for(i = 0; i < uiCnt; ++i)
    {
        /* wait the end of conversion flag */
        while(!adc_flag_get(adc_periph, ADC_FLAG_EOC));
        /* clear the end of conversion flag */
        adc_flag_clear(adc_periph, ADC_FLAG_EOC);
        /* get regular channel sample value */
        usValueNow = adc_regular_data_read(adc_periph);

        uiValueSum += usValueNow;;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }


    /* 去除最大与最小值 */
    uiValueSum -= (usValueMax + usValueMin);

    return ((float)uiValueSum / (uiCnt - 2) * (3.3f / 4095.0f));
}
